package gnssio

import (
	"dgo/goutils/utils"
	"fmt"
	"net"
	"sync/atomic"
	"time"
)

// 连接handle
var __commtcpsvr_handle_counter uint32 = 1

// 连接对象
type CommTcpSvrClientConnection struct {
	handle     uint32
	conn       net.Conn
	owner      *CommTcpSvr
	sendQueue  *utils.QueueTask
	remoteAddr string

	closeFlag int32
	recvbytes int64
	sendbytes int64

	connecttime  time.Time
	distime      time.Time
	lastsendtime time.Time
	lastrecvtime time.Time
	TagPtr       interface{}

	Send_monitor utils.MonitorSpeedSizeRec
	Recv_monitor utils.MonitorSpeedSizeRec
	LastWarning  string

	disReason  string
	OnDisEvent func(sender *CommTcpSvrClientConnection)
}

func NewCommTcpSvrClientConnection(conn net.Conn, tcpSvr *CommTcpSvr) *CommTcpSvrClientConnection {
	rval := &CommTcpSvrClientConnection{
		handle: atomic.AddUint32(&__commtcpsvr_handle_counter, 1),
		conn:   conn,
		owner:  tcpSvr,
	}
	if conn != nil {
		rval.remoteAddr = conn.RemoteAddr().String()
	}
	rval.sendQueue = utils.NewQueueTask(rval.onSendQueueWork)
	if tcpSvr.MonitorFlag >= 1 {
		utils.Monitor.AddMonitorRec(fmt.Sprintf("%s_%d_recv", tcpSvr.id, rval.handle), &rval.Recv_monitor)
		utils.Monitor.AddMonitorRec(fmt.Sprintf("%s_%d_send", tcpSvr.id, rval.handle), &rval.Send_monitor)
	}
	return rval
}

func (self *CommTcpSvrClientConnection) Start() {
	utils.GoFunc2(self.handleRecv)
	if self.owner.UseQueueSend {
		self.sendQueue.Start()
	}
}

func (self *CommTcpSvrClientConnection) GetHandle() uint32 {
	return self.handle
}

func (self *CommTcpSvrClientConnection) GetRemoteAddr() string {
	return self.conn.RemoteAddr().String()
}

func (self *CommTcpSvrClientConnection) Status() string {
	var sb utils.BytesBuilder
	if self.distime.IsZero() {
		sb.Appendf("状态:在线, 连接时长:%s", utils.DurationStr(time.Now().Sub(self.connecttime)))
	} else {
		sb.Appendf("状态:离线(%s), 连接时长:%s", self.disReason, utils.DurationStr(self.distime.Sub(self.connecttime)))
	}
	sb.AppendStr(",")
	sb.Appendf("sendbytes:%s, recvbytes:%s", utils.HumanFilesize(self.sendbytes), utils.HumanFilesize(self.recvbytes))
	return sb.String()
}

func (this *CommTcpSvrClientConnection) onSendQueueWork(args ...interface{}) {
	buf := args[0].([]byte)
	this.innerSend(buf)
}

func (self *CommTcpSvrClientConnection) GetLastActivityT() time.Time {
	rval := self.connecttime
	if rval.IsZero() || (!self.lastrecvtime.IsZero() && rval.Before(self.lastrecvtime)) {
		rval = self.lastrecvtime
	}

	if rval.IsZero() || (!self.lastsendtime.IsZero() && rval.Before(self.lastsendtime)) {
		rval = self.lastsendtime
	}

	return rval
}

func (self *CommTcpSvrClientConnection) checkKickOut(isec int) {

	lastT := self.GetLastActivityT()
	if lastT.IsZero() {
		self.disReason = fmt.Sprintf("%s 未进行任何数据交互,请求断开连接", self.conn.RemoteAddr().String())
		utils.Log.WarnTypef("BUG", self.disReason)
		self.RequestDisconnect()
		return
	}

	t := time.Since(lastT)
	tick := int(t.Seconds())
	if tick <= isec {
		//utils.Log.Debugf("%s 超时检测,%d秒，未进行数据交互", self.conn.RemoteAddr().StatusString(), tick)
		return
	}

	self.disReason = fmt.Sprintf("%s 超时%d秒，未进行数据交互,请求断开连接", self.conn.RemoteAddr().String(), tick)
	// utils.Log.Debugf(self.disReason)
	self.RequestDisconnect()
}

func (this *CommTcpSvrClientConnection) GetDisReason() string {
	return this.disReason
}

func (this *CommTcpSvrClientConnection) RequestDisconnect() {
	// 避免重复关闭
	if !atomic.CompareAndSwapInt32(&this.closeFlag, 0, 1) {
		return
	}
	utils.GoFunc2(this.sendQueue.Stop)
	this.owner.removeOnline(this)
	this.conn.Close()
	utils.Monitor.RemoveMonitorRec(fmt.Sprintf("%s_%d_recv", this.owner.id, this.handle))
	utils.Monitor.RemoveMonitorRec(fmt.Sprintf("%s_%d_send", this.owner.id, this.handle))
}

func (this *CommTcpSvrClientConnection) innerSend(buf []byte) {
	if this.closeFlag == 1 { // 已经关闭
		return
	}

	n, err := this.conn.Write(buf)
	if err != nil {
		if len(this.disReason) == 0 {
			this.disReason = fmt.Sprintf("%s 处理发送数据时出现了异常:%v", this.conn.RemoteAddr().String(), err)
		}
		this.RequestDisconnect()
	} else {
		if this.owner.MonitorFlag >= 1 {
			this.Send_monitor.Delta(int64(n))
		}
		this.lastsendtime = time.Now()
		this.sendbytes = this.sendbytes + int64(n)
		this.owner.NetInfo.DoSendBytes(uint64(n))
	}
}

func (this *CommTcpSvrClientConnection) DirectlySendBuffer(buf []byte) (int, error) {
	if this.closeFlag == 1 { // 已经关闭
		return 0, fmt.Errorf("连接已经关闭")
	}

	n, err := this.conn.Write(buf)
	if err != nil {
		if len(this.disReason) == 0 {
			this.disReason = fmt.Sprintf("%s 处理发送数据时出现了异常:%v", this.conn.RemoteAddr().String(), err)
		}
	} else {
		if this.owner.MonitorFlag >= 1 {
			this.Send_monitor.Delta(int64(n))
		}
		this.lastsendtime = time.Now()
		this.sendbytes = this.sendbytes + int64(n)
		this.owner.NetInfo.DoSendBytes(uint64(n))
	}
	return n, err
}

func (this *CommTcpSvrClientConnection) Send(buf []byte, l int) {
	sendBuf := buf
	if l > 0 {
		sendBuf = buf[:l]
	}

	if this.owner.UseQueueSend {
		//cpyBuf := make([]byte, len, len);
		//copy(cpyBuf, buf);
		err := this.sendQueue.Push(sendBuf)
		if err != nil {
			this.LastWarning = fmt.Sprintf("[%s]压入队列异常:%s", utils.NowString(), err.Error())
			utils.Log.Warnf("[%s]入队列出现异常:%s", this.remoteAddr, err.Error())
		}
	} else {
		this.innerSend(sendBuf)
	}
}

// 处理连接
func (this *CommTcpSvrClientConnection) handleRecv() {
	this.owner.NetInfo.DoConnect()
	defer this.owner.NetInfo.DoDisconnect()

	for {
		// 避免异步修改
		buffer := make([]byte, this.owner.BlockRecvSize)
		n, err := this.conn.Read(buffer)
		if err != nil {
			if len(this.disReason) == 0 {
				this.disReason = fmt.Sprintf("%s 处理接受请求时出现了异常: %v", this.conn.RemoteAddr().String(), err)
				// utils.Log.Debugf("%s 处理接受请求时出现了异常: %v", this.conn.RemoteAddr().StatusString(), err)
			}
			this.RequestDisconnect()
			return
		}
		this.owner.NetInfo.DoRecvBytes(uint64(n))
		if this.owner.MonitorFlag >= 1 {
			this.Recv_monitor.Delta(int64(n))
		}

		this.lastrecvtime = time.Now()
		this.recvbytes += int64(n)

		this.owner.onRecvBuffer(this, buffer, n)
	}
}
